<?php
namespace Lib;
use Lib\Encryption\DriverAbstract,
    Lib\Encryption\DriverFactory,
    Lib\Encryption\DriverInterface,
    Lib\Encryption\DriverException,
    Lib\Encryption\EncryptionException;
/**
 * Enter description here ...
 * 
 * @author diotheos
 * @package Encryption
 */
class Encryption{
    
    const ENCRYPT_MODE_NONE  = 1;
    const ENCRYPT_MODE_VALUE = 2;
    
    const ENCRYPT_DECODE_FUNC = 'decode';
    const ENCRYPT_ENCODE_FUNC = 'encode';

    /**
     * @var DriverInterface
     */
    protected $_driver = null;
    
    public $_encryptMode;
    /**
     * Set current driver
     *  
     * @param DriverAbstract $driver
     */
    public function setDriver(DriverAbstract $driver){
        $this->_driver = $driver;
    }
    
    /**
     * Init new driver and set it to defaults
     * 
     * @param string $driverName
     * @param array $driverOptions
     */
    public function initDriver($driverName, $driverOptions = array()){
        $this->setDriver(DriverFactory::factory($driverName, $driverOptions));
    }
    
    /**
     * Get current Driver
     * 
     * @return DriverAbstract
     */
    public function getDriver(){
        if(!$this->_driver instanceof DriverAbstract){
            throw new DriverException('Encryption driver is not loaded');
        }
        return $this->_driver;
    }

    /**
     * 
     * Enter description here ...
     * @param string $hash
     */
    public function decode($hash = null){
        return $this->getDriver()->decode($hash);
    }
    
    /**
     * Enter description here ...
     * @param Data $data
     */
    public function decodeAll(Data $data){
        $this->_transformEncryption(self::ENCRYPT_DECODE_FUNC, $data);
    }
    
    /**
     * Enter description here ...
     * @param Data $data
     */
    public function encodeAll(Data $data){
        $this->_transformEncryption(self::ENCRYPT_ENCODE_FUNC, $data);
    }
    
    /**
     * Enter description here ...
     * 
     * @param string $item
     */
    public function encode($item = null){
        return $this->getDriver()->encode($item);
    }
    
	/**
     * Sets current encrypt mode
     * 
     * @param int $mode
     */
    public function setEncryptMode($mode = self::ENCRYPT_MODE_NONE){
        $this->_encryptMode = $mode;
    }
    
    /**
     * Get current encrypt mode
     * 
     * @return string
     */
    public function getEncryptMode(){
        return $this->_encryptMode;
    }
    

	/**
     * Transform data encryption
     * @return bool
     */
    private function _transformEncryption($func, Data $data){
        if(!($func == self::ENCRYPT_DECODE_FUNC || $func == self::ENCRYPT_ENCODE_FUNC)){
            throw new EncryptionException('Unknown encryption transform function '.$func.'()');
        }
        
        if(!count($data)) return false;
        switch ($this->getEncryptMode()){
            case self::ENCRYPT_MODE_NONE:
                return false;
            break;
                
            case self::ENCRYPT_MODE_VALUE:
                foreach ($data as $key => $value) {
                    $data->setValue($key, $this->$func($value));
                }
            break;

            default:
                throw new EncryptionException('Unknown encrypt mode '.$this->getEncryptMode());
            break;
        }
        return true;
    }
    
    /**
     * @param DriverAbstract | string $driver
     * @param unknown_type $params
     */
    public function __construct($driver = null, $params = array()){
        $this->setEncryptMode(self::ENCRYPT_MODE_VALUE);
        if (null !== $driver){
            if(is_object($driver)){
                if(! $driver instanceof DriverInterface){
                    throw new EncryptionException('Given driver is not instance if DriverInterface');
                } else {
                    $driver->setOptions($params);
                    $this->setDriver($driver);
                }
            } else {
                $this->initDriver($driver, $params);
            }
        }
    }
}